package thread;

/**
 * 死锁的例子
 * 1，同步块：获取的对象锁是synchronized(flag)中的flag对象锁。
 * 2，同步方法：获取的是方法所属的类对象，及类对象锁。
 * 静态同步方法，由于多个线程都会共享，所以一定会同步。
 * 而非静态同步方法，只有在单例模式下才会同步。
 */
public class ConsumerAndProducerThread {
    public static void main(String[] args) {
        Storage storage = new Storage(40,100);
        Producer p = new Producer(70,storage);		//生产
        p.start();
        Consumer c = new Consumer(50, storage);
        c.start();
    }
}

/**
 * 消费者
 *
 * @author ciding
 * @createTime Dec 12, 2011 3:05:35 PM
 *
 */
class  Consumer extends Thread {
    private int neednum; 		// 生产产品的数量
    private Storage storage; 	// 仓库

    Consumer(int neednum, Storage storage) {
        this.neednum = neednum;
        this.storage = storage;
    }

    public void run() {
        storage.consume(neednum);// 消费指定数量的产品
    }
}

/**
 * 生产者
 *
 * @author ciding
 * @createTime Dec 12, 2011 3:06:03 PM
 *
 */
class Producer extends Thread {
    private int neednum; 		// 生产产品的数量
    private Storage storage; 	// 仓库

    Producer(int neednum, Storage storage) {
        this.neednum = neednum;
        this.storage = storage;
    }

    public void run() {
        storage.produce(neednum);	// 生产指定数量的产品
    }
}

/**
 * 仓库
 *
 * @author ciding
 * @createTime Dec 12, 2011 3:06:31 PM
 *
 */
class Storage {
    public int max_size = 100;	// 库存量初始值
    public int curnum = 0;		// 当前库存量初始值

    Storage() {
    }

    Storage(int curnum, int max_size) {
        this.curnum = curnum;
        this.max_size = max_size;
    }

    /**
     * 生产指定数量的产品
     *
     * @param neednum
     */
    public synchronized void produce(int neednum) {
		/* 测试是否需要生产 */
        while (neednum + curnum > max_size) {
            try {
                Thread.sleep(100);	//模拟运行时间

                System.out.println("要生产的产品数量" + neednum + "超过剩余库存量"
                        + (max_size - curnum) + "，暂时不能执行生产任务!");
                wait();		// 当前的生产线程等待
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        curnum += neednum; // 满足生产条件，则进行生产，这里简单的更改当前库存量
        System.out.println("已经生产了" + neednum + "个产品，现仓储量为" + curnum);

        notify(); // 唤醒在此对象监视器上等待的某个线程
    }

    /**
     * 消费指定数量的产品
     *
     * @param neednum
     */
    public synchronized void consume(int neednum) {
        // 测试是否可消费
        while (curnum < neednum) {
            try {
                Thread.sleep(100);//模拟运行时间

                System.out.println("仓储量为:" + curnum + "，不够消费:" + neednum);
                wait();// 当前的生产线程等待
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        curnum -= neednum; // 满足消费条件，则进行消费，这里简单的更改当前库存量
        System.out.println("已经消费了" + neednum + "个产品，现仓储量为" + curnum);

        notify(); // 唤醒在此对象监视器上等待的某个线程
    }
}
